package SSF.OS.OSPFv2.test;

/**
 * OSPFDumpPro.java
 *
 * This is a modified DumpPro, which dumps OSPF packets. Parts of the code
 * were taken from SSF.OS.DumpPro.
 * 
 * @version 0.2.1
 */

import java.io.*;
import java.util.Calendar;

import SSF.OS.*;
import SSF.OS.OSPFv2.*;

/** A standalone class that translates binaryTcpDump files into ASCII
  *  format. This is a modified DumpPro, which dumps OSPF packets. Parts of the code
  * were taken from SSF.OS.DumpPro.
  */
public class OSPFDumpPro  {

  /********************* Attribute Variables *********************/

class DumpFileHeader {
  int magic;   //magic number for tcpdump files
  int major;   //major version number
  int minor;   //minor version number
  int zone;    // gmt to local correction
  int sigfigs; //accuracy of timestamp
  int snaplen; //max length saved portion of each packet
  int linktype;//datalink type
}
class PktHeader {
  int second;
  int microsec;
  int portion;
  int pktlen;
}

  class IPHeader{
    byte ip_ver;       // ip version number
    byte type_ser;     // type of service
    short byte_count;  //byte count of ip packet
    short data_id;     //datagram id
    short flag_offset; //flag and fragment offset
    byte ttl;          //time to live
    byte pro_num;      //ip protocol number
    short ip_checksum; //ip header check sum
    int src_ip;        // source ip address
    int dest_ip;       //destination ip address
  }
  
  static final int DLT_NULL = 0;       /* no link-layer encapsulation */
  static final int DLT_EN10MB = 1;       /* Ethernet (10Mb) */
  static final int DLT_SLIP = 8;       /* Serial Line IP */
  static final int DLT_FDDI = 10;      /* FDDI */
  static final int DLT_RAW = 12;      /* raw IP */
  
  /* 2001-10-16, Dirk Jacob: Extensions for OSPF */
  class OSPFHeader {
  	byte version;
  	byte type;
  	short len;
  	int routerID;
  	int areaID;
  	short checksum;
  	short auType;
  	int auth1;
  	int auth2;
  	Object ospfData;
  }
  
  class OSPFHelloPkt {
  	int netmask;
  	short helloInterval;
  	byte options;
  	byte priority;
  	int deadInterval;
  	int dr;
  	int bdr;
  	int num_nbrs;
  	int[] neighbors;
  }

  class OSPFDDPkt {
  	short interfaceMTU;
  	byte options;
  	byte flags; 
  	int ddsequence;
  	int num_headers;
  	LSAHdr[] lsaheaders;
  }

  class OSPFLSReqPkt {
  	int num_reqs;
	LSAId[] reqlsas;
  }
  
  class OSPFLSUpdPkt {
  	int numlsa;
  	LSAHdr[] lsas;
  }

  class OSPFLSAckPkt {
  	int num_lsas;
  	LSAHdr[] lsas;
  }

  class LSAId {
  	int lstype;
  	int lsid;
  	int advrouter;
  }

  class LSAHdr {
  	short lsage;
  	byte options;
  	byte linktype;
  	int lsid;
  	int advrouter;
  	int lssequence;
  	short lschecksum;
  	short len;
  	Object lsaData;
  }

  class RtrLSA {
  	byte flags;
  	byte nul;	
  	short numlinks;
  	RtrLink[] links;
  }
  
  class RtrLink {
  	int linkid;
  	int linkdata;
  	byte linktype;
  	byte numtos;
  	short metric;
  	byte tos;
  	byte tos_null;
  	short tos_metric;
  }
	
  /* other LSAs aren't implemented yet in SSF.OS.OSPF */

  /* end dj, 2001-10-16 */

  DataInputStream in;
  boolean swap = false;
  int link_hdr_len = 0;
  /************************* Constructors ************************/

  public OSPFDumpPro(String infile, String option) throws IOException{
    in = new DataInputStream(new BufferedInputStream(new FileInputStream(infile)));

    if(option.compareTo("") == 0)
      format();
  }
  /************************ Class Methods ***********************/

  /** read information from binary tcpdump file header */
  public DumpFileHeader getFileHeader() throws IOException{
    byte[] b4 = new byte[4];
    DumpFileHeader hdr = new DumpFileHeader();
    int n = 0;
    if((n = in.read(b4)) != -1){
      hdr.magic = byteToInt(swap, b4);
      if(hdr.magic != 0xA1B2C3D4){
	if(hdr.magic != 0xD4C3B2A1){
	  System.err.println("Wrong file type");
	  System.exit(0);
	}else {
	  swap = !swap;
	}  
      } 
    }
    if((n = in.read(b4)) != -1){
      n = byteToInt(swap, b4);
      hdr.major = n >> 16;
      hdr.minor = n - (hdr.major << 16);
    }
    if((n = in.read(b4)) != -1){
      hdr.zone = byteToInt(swap, b4);
    } 
    if((n = in.read(b4)) != -1){
      hdr.sigfigs =byteToInt(swap, b4);
    } 
    if((n = in.read(b4)) != -1){
      hdr.snaplen = byteToInt(swap, b4);
    } 
    if((n = in.read(b4)) != -1){
      hdr.linktype = byteToInt(swap, b4);
    } 
    return hdr;
  }
 
  /** read packet tcpdump header */
  public PktHeader getPktHeader() throws IOException{
    byte b4[] = new byte[4];
    int n = 0;

    PktHeader hdr = new PktHeader();/* 20 bytes 5 fields*/
    if((n = in.read(b4)) != -1){
      hdr.second = byteToInt(swap, b4); 
    }
    if((n = in.read(b4)) != -1){
      hdr.microsec = byteToInt(swap, b4); 
    }
    if((n = in.read(b4)) != -1){
      hdr.portion = byteToInt(swap, b4);
    } 
    if((n = in.read(b4)) != -1){
      hdr.pktlen = byteToInt(swap, b4);
    }
    if(n == -1) return null;
    return hdr;
  }
  int init_second;
  int init_microsec;
  public double getTime(PktHeader hdr)throws IOException{
    double sec = (double)(hdr.second - init_second);
    double msec = (double)(hdr.microsec - init_microsec);
    return sec + msec/(double)1000000;
  }
  /** read ip header */
  public IPHeader getIpHeader()throws IOException{

    byte b2[] = new byte[2];
    byte b4[] = new byte[4];
    int n = 0;
    IPHeader hdr = new IPHeader();/* 20 bytes 10 fields*/
    hdr.ip_ver = in.readByte();
    hdr.type_ser = in.readByte(); 
    if((n = in.read(b2)) != -1){
      hdr.byte_count = (short)byteToInt(false, b2); 
    }
    if((n = in.read(b2)) != -1){
      hdr.data_id = (short)byteToInt(false, b2);
      
    }
    if((n = in.read(b2)) != -1){
      hdr.flag_offset = (short)byteToInt(false, b2); 
    }
    hdr.ttl = in.readByte();
    hdr.pro_num =  in.readByte();
    if((n = in.read(b2)) != -1){
      hdr.ip_checksum = (short)byteToInt(false, b2); 
    }
    if((n = in.read(b4)) != -1){
      hdr.src_ip = byteToInt(false, b4); 
    }
    if((n = in.read(b4)) != -1){
      hdr.dest_ip = byteToInt(false, b4); 
    }
    if(n == -1)return null;
    return hdr;
  }
  public int[] scanForIpAddr() throws IOException{
    byte b4[] = new byte[4];
    int ipAddr[] = new int[2];
    
    in.skipBytes(12);
    int n = in.read(b4);
    if(n != -1){
      ipAddr[0] = byteToInt(false, b4);
    }
    if((n = in.read(b4)) != -1){
      ipAddr[1] = byteToInt(false, b4);
    }
    if(n == -1)return null;
    return ipAddr;
  }

  /* filter variable */
  static double stime = 0;   //print time series between stime and etime
  static double etime = Double.MAX_VALUE; 
  static int sip = -1;//print when source IP and destination IP are matched
  static int dip = -1; // -1 is wildcast   
  static int sport = -1; // -1 is wildcast   
  static int dport = -1; // -1 is wildcast   
                      
  static byte flag_mask = (byte)0;  //   Mask bit to find SYN, FIN, ACK
  static boolean data = false;    // if true print packet only contains data 

  /** output with standard format */
  public void format(){
    try {
      DumpFileHeader hdr = getFileHeader();
      switch (hdr.linktype) {
      case DLT_NULL:
	link_hdr_len = 4;
	break;
      case DLT_EN10MB:
	link_hdr_len = 14;
	break; 
      case DLT_SLIP:
	link_hdr_len = 16;
	break; 
      case DLT_FDDI:
	link_hdr_len = 13+8;
	break; 
      case DLT_RAW:
	link_hdr_len = 0;
	break; 
      default:
	System.out.println("Unknown link type value: " + hdr.linktype);
	System.exit(0);
	break;
      }   // end of switch (linktype)

      PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

      PktHeader pkHeader;
      StringBuffer lineBuffer = new StringBuffer(200);
      while((pkHeader = getPktHeader()) != null){
	double time = getTime(pkHeader);
	int cap_len = (pkHeader.pktlen<pkHeader.portion)?
					pkHeader.pktlen:pkHeader.portion;

	if(time < stime) {
	  in.skipBytes(cap_len);
	  continue;
	}
        if(time > etime) break; //stop scan, suppose timestamp is in order
	in.skipBytes(link_hdr_len);
	IPHeader ipHdr = getIpHeader();

	/* Dirk Jacob, 2001-10-16 -- OSPF */
	if(ipHdr.pro_num == Protocols.OSPF_PRTL_NUM)
	  OspfFormat(pkHeader, ipHdr, cap_len, out);
	/* end djacob */
      }

      in.close();
      out.close();
    } catch (IOException e) {
      System.err.println(e);
    } 
  }
  /* Dirk Jacob, 2001-10-16 -- OSPF */
  public OSPFHeader getOspfHeader() throws IOException {
  	byte b2[] = new byte[2];
  	byte b4[] = new byte[4];
  	int n = 0;
  	int i;
  	int j;
  	
  	OSPFHeader hdr = new OSPFHeader();
  	
  	/* standard OSPF Header */
  	hdr.version = in.readByte();
  	hdr.type = in.readByte();
  	
  	if((n = in.read(b2)) != -1) {
  		hdr.len = (short)byteToInt(false, b2);
  	}
  	if((n = in.read(b4)) != -1) {
  		hdr.routerID = byteToInt(false, b4);
  	}
  	if((n = in.read(b4)) != -1) {
  		hdr.areaID = byteToInt(false, b4);
  	}
  	if((n = in.read(b2)) != -1) {
  		hdr.checksum = (short)byteToInt(false, b2);
  	}
  	if((n = in.read(b2)) != -1) {
  		hdr.auType = (short)byteToInt(false, b2);
  	}
  	if((n = in.read(b4)) != -1) {
  		hdr.auth1 = byteToInt(false, b4);
  	}
  	if((n = in.read(b4)) != -1) {
  		hdr.auth2 = byteToInt(false, b4);
  	}
  	
  	switch(hdr.type) {
  		case Packet.HELLO:
  			hdr.ospfData = new OSPFHelloPkt();
  			
  			if((n = in.read(b4)) != -1) {
  				((OSPFHelloPkt)(hdr.ospfData)).netmask = byteToInt(false, b4);
  			}
  			if((n = in.read(b2)) != -1) {
  				((OSPFHelloPkt)(hdr.ospfData)).helloInterval = (short)byteToInt(false, b2);
  			}
  			((OSPFHelloPkt)(hdr.ospfData)).options = in.readByte();
  			((OSPFHelloPkt)(hdr.ospfData)).priority = in.readByte();
  			if((n = in.read(b4)) != -1) {
  				((OSPFHelloPkt)(hdr.ospfData)).deadInterval = byteToInt(false, b4);
  			}
  			if((n = in.read(b4)) != -1) {
  				((OSPFHelloPkt)(hdr.ospfData)).dr = byteToInt(false, b4);
  			}
  			if((n = in.read(b4)) != -1) {
  				((OSPFHelloPkt)(hdr.ospfData)).bdr = byteToInt(false, b4);
  			}
  			i = (hdr.len - 44)/4;
  			j = i;
  			
  			((OSPFHelloPkt)(hdr.ospfData)).num_nbrs = i;
  			((OSPFHelloPkt)(hdr.ospfData)).neighbors = new int[i];
  			while(i > 0) {
  				if((n = in.read(b4)) != -1) {
  					((OSPFHelloPkt)(hdr.ospfData)).neighbors[j-i] = byteToInt(false, b4);
  				}	
  				i--;
  			}
  			break;
  		case Packet.DATABASE:
  			hdr.ospfData = new OSPFDDPkt();
  			
  			if((n = in.read(b2)) != -1) {
  				((OSPFDDPkt)(hdr.ospfData)).interfaceMTU = (short)byteToInt(false, b2);
  			}
  			((OSPFDDPkt)(hdr.ospfData)).options = in.readByte();
  			((OSPFDDPkt)(hdr.ospfData)).flags = in.readByte();
  			if((n = in.read(b4)) != -1) {
  				((OSPFDDPkt)(hdr.ospfData)).ddsequence = (short)byteToInt(false, b4);
  			}
  			i = (hdr.len - 32) / 20;
			j = i;  			
  			((OSPFDDPkt)(hdr.ospfData)).num_headers = i;
  			((OSPFDDPkt)(hdr.ospfData)).lsaheaders = new LSAHdr[i];
  			while(i > 0) {
  				LSAHdr l = new LSAHdr();
  				if((n = in.read(b2)) != -1) {
  					l.lsage = (short)byteToInt(false, b2);
  				}
  				l.options = in.readByte();
  				l.linktype = in.readByte();
  				if((n = in.read(b4)) != -1) {
  					l.lsid = byteToInt(false, b4);
  				}
  				if((n = in.read(b4)) != -1) {
  					l.advrouter = byteToInt(false, b4);
  				}
  				if((n = in.read(b4)) != -1) {
  					l.lssequence = byteToInt(false, b4);
  				}
  				if((n = in.read(b2)) != -1) {
  					l.lschecksum = (short)byteToInt(false, b2);
  				}
  				if((n = in.read(b2)) != -1) {
  					l.len = (short)byteToInt(false, b2);
  				}
  		
  				((OSPFDDPkt)(hdr.ospfData)).lsaheaders[j-i] = l;
  				i--;
  			}
  			break;
  		case Packet.LSREQUEST:  			
  			hdr.ospfData = new OSPFLSReqPkt();
  			
  			i = (hdr.len - 24) / 12;
			j = i;  			
  			((OSPFLSReqPkt)(hdr.ospfData)).num_reqs = i;
  			((OSPFLSReqPkt)(hdr.ospfData)).reqlsas = new LSAId[i];
  			while(i > 0) {
  				LSAId lr = new LSAId();
  				
  				if((n = in.read(b4)) != -1) {
  					lr.lstype = byteToInt(false, b4);
  				}
  				if((n = in.read(b4)) != -1) {
  					lr.lsid = byteToInt(false, b4);
  				}
  				if((n = in.read(b4)) != -1) {
  					lr.advrouter = byteToInt(false, b4);
  				}
  				
  				((OSPFLSReqPkt)(hdr.ospfData)).reqlsas[j-i] = lr;
  				i--;
  			}
  			
  			
  			break;
  		case Packet.LSUPDATE:  			
  			hdr.ospfData = new OSPFLSUpdPkt();
  			
  			if((n = in.read(b4)) != -1) {
  				((OSPFLSUpdPkt)(hdr.ospfData)).numlsa = byteToInt(false, b4);
  			}
  			
  			i = ((OSPFLSUpdPkt)(hdr.ospfData)).numlsa;
  			((OSPFLSUpdPkt)(hdr.ospfData)).lsas = new LSAHdr[i];
  			j = i;
  			
  			while( i > 0 ) {
  				
  				((OSPFLSUpdPkt)(hdr.ospfData)).lsas[j-i] = getOspfLsa();
  				i--;
  			}	
  			break;
  		case Packet.LSACK:  			
  			hdr.ospfData = new OSPFLSAckPkt();
  			
  			i = (hdr.len - 24) / 20;
			j = i;
		
  			((OSPFLSAckPkt)(hdr.ospfData)).num_lsas = i;
  			((OSPFLSAckPkt)(hdr.ospfData)).lsas = new LSAHdr[i];
  			while(i > 0) {
  				LSAHdr lh = new LSAHdr();
  				if((n = in.read(b2)) != -1) {
  					lh.lsage = (short)byteToInt(false, b2);
  				}
  				lh.options = in.readByte();
  				lh.linktype = in.readByte();
  				if((n = in.read(b4)) != -1) {
  					lh.lsid = byteToInt(false, b4);
  				}
  				if((n = in.read(b4)) != -1) {
  					lh.advrouter = byteToInt(false, b4);
  				}
  				if((n = in.read(b4)) != -1) {
  					lh.lssequence = byteToInt(false, b4);
  				}
  				if((n = in.read(b2)) != -1) {
  					lh.lschecksum = (short)byteToInt(false, b2);
  				}
  				if((n = in.read(b2)) != -1) {
  					lh.len = (short)byteToInt(false, b2);
  				}
  		
  				((OSPFLSAckPkt)(hdr.ospfData)).lsas[j-i] = lh;
  				i--;
  			}
  			break;
  		default:
  			int l = hdr.len - 24;
  			if( l > 0) in.skipBytes(l);
  			hdr.ospfData = null;
  			break;
  	}
  	
  	return hdr;
  }
  
  private LSAHdr getOspfLsa() throws IOException {
  	byte b2[] = new byte[2];
  	byte b4[] = new byte[4];
  	int n = 0;
  	
  	LSAHdr lh = new LSAHdr();
  	
  	if((n = in.read(b2)) != -1) {
  		lh.lsage = (short)byteToInt(false, b2);
  	}
  	lh.options = in.readByte();
  	lh.linktype = in.readByte();
  	if((n = in.read(b4)) != -1) {
  		lh.lsid = byteToInt(false, b4);
  	}
  	if((n = in.read(b4)) != -1) {
  		lh.advrouter = byteToInt(false, b4);
  	}
  	if((n = in.read(b4)) != -1) {
  		lh.lssequence = byteToInt(false, b4);
  	}
  	if((n = in.read(b2)) != -1) {
  		lh.lschecksum = (short)byteToInt(false, b2);
  	}
  	if((n = in.read(b2)) != -1) {
  		lh.len = (short)byteToInt(false, b2);
  	}
  	
  	switch(lh.linktype) {
  		case LSA.ROUTER_LSA:
  			RtrLSA rtrlsa = new RtrLSA();
  			
  			rtrlsa.flags = in.readByte();		
  			rtrlsa.nul = in.readByte();
  			if((n = in.read(b2)) != -1) {
  				rtrlsa.numlinks = (short)byteToInt(false, b2);
  			}
  			
  			rtrlsa.links = new RtrLink[rtrlsa.numlinks];
  			for( int i = 0; i < rtrlsa.numlinks; i++ ) {
  				RtrLink lnk = new RtrLink();
  				
  				if((n = in.read(b4)) != -1) {
  					lnk.linkid = byteToInt(false, b4);
  				}
  				if((n = in.read(b4)) != -1) {
  					lnk.linkdata = byteToInt(false, b4);
  				}
  				lnk.linktype = in.readByte();
  				lnk.numtos = in.readByte();
  				if((n = in.read(b2)) != -1) {
  					lnk.metric = (short)byteToInt(false, b2);
  				}	
  				
  				/* don't read any TOS metrics, because they weren't written */
  				rtrlsa.links[i] = lnk;
  			}
  			
  			lh.lsaData = rtrlsa;
  			break;
  		case LSA.NETWORK_LSA:
  		case LSA.SUMMARY_NETWORK_LSA:
  		case LSA.SUMMARY_ASBR_LSA:
  		case LSA.AS_EXTERNAL_LSA:
  		default:
  			int l = lh.len - 20;
  			if (l > 0) {
  				in.skipBytes(l);
  			}
  			lh.lsaData = null;
  			break;
  	}
  	
  	return lh;
  }

  private void OspfFormat(PktHeader pkHeader, IPHeader ipHdr, int cap_len, PrintWriter out){
  	
  	StringBuffer lineBuffer = new StringBuffer(200);	
  	try {
  		OSPFHeader ospfHdr = getOspfHeader();
  		
  		// no bytes to skip here - we always read the complete OSPF packet!
  		
  		if((sip != -1)&&(sip != ipHdr.src_ip)) return;
      		if((dip != -1)&&(dip != ipHdr.dest_ip)) return;
      		
      		// the standard output: timestamp, src and dest address
      		long second = pkHeader.second & 0xffffffffL;
      		long min = second/60;
      		long hour = (min/60)%24;
      		float sec = second - 60*min + pkHeader.microsec/(float)1000000;
      		min = min%60;
      		lineBuffer.append(hour<10?"0":"").append(hour).append(":")
			.append(min<10?"0":"").append(min).append(":")
			.append(sec<10?"0":"").append(sec).append(" ");
      		lineBuffer.append(IPtoString(ipHdr.src_ip))
			.append(" > ").append(IPtoString(ipHdr.dest_ip));
			
		// now do the ospf specific output
		lineBuffer.append(": OSPFv").append(ospfHdr.version)
			.append("-");
		
		String t;
		
		switch(ospfHdr.type) {
			case Packet.HELLO:
				t = "hello";
				break;
			case Packet.DATABASE:
				t = "dd";
				break;
			case Packet.LSREQUEST:
				t = "ls_req";
				break;
			case Packet.LSUPDATE:
				t = "ls_upd";
				break;
			case Packet.LSACK:
				t = "ls_ack";
				break;
			default:
				t = "type"+ospfHdr.type;
				break;
		}
		
		lineBuffer.append( t ).append(" ").append( ospfHdr.len ).append(":");
		
		if(ipHdr.src_ip != ospfHdr.routerID)
			lineBuffer.append(" rtrid ").append( IPtoString(ospfHdr.routerID) );
		
		if(ospfHdr.areaID != 0)
			lineBuffer.append(" area ").append( IPtoString(ospfHdr.areaID) );
		else
			lineBuffer.append(" backbone");
		
		/* authentication should be placed here */
				
		switch(ospfHdr.type) {
			case Packet.HELLO:
				OSPFHelloPkt helloPkt = (OSPFHelloPkt)ospfHdr.ospfData;
				if(helloPkt == null) break;
				
				lineBuffer.append(ospf_get_option_string(helloPkt.options));
				lineBuffer.append(" mask ").append(IPtoString(helloPkt.netmask));
				lineBuffer.append(" int ").append(helloPkt.helloInterval);
				lineBuffer.append(" pri ").append(helloPkt.priority);
				lineBuffer.append(" dead ").append(helloPkt.deadInterval);
				
				if(helloPkt.dr != 0) 
					lineBuffer.append(" dr ").append(IPtoString(helloPkt.dr));
				
				if(helloPkt.bdr != 0) 
					lineBuffer.append(" bdr ").append(IPtoString(helloPkt.bdr));
					
				if(helloPkt.num_nbrs > 0) {
					lineBuffer.append(" nbrs");
					for(int i = 0; i < helloPkt.num_nbrs; i++) {
						lineBuffer.append(" ");
						lineBuffer.append(IPtoString(helloPkt.neighbors[i]));
					}
				}
				
				break;
			case Packet.DATABASE:
				OSPFDDPkt ddPkt = (OSPFDDPkt)ospfHdr.ospfData;
				if(ddPkt == null) break;
				
				lineBuffer.append(ospf_get_option_string(ddPkt.options));
				String sep = " ";
				if((ddPkt.flags & 0x04) > 0) {
					lineBuffer.append(sep).append("I");
					sep = "/";
				}
				if((ddPkt.flags & 0x02) > 0) {
					lineBuffer.append(sep).append("M");
					sep = "/";
				}
				if((ddPkt.flags & 0x01) > 0) {
					lineBuffer.append(sep).append("MS");
					sep = "/";
				}
				
				/* orignal tcpdump outputs seq no as hex */
				lineBuffer.append(" S ").append(Integer.toHexString(ddPkt.ddsequence));
				
				/* original tcpdump doesn't show the MTU */
				lineBuffer.append(" mtu ").append(ddPkt.interfaceMTU);
				
				for(int i = 0; i < ddPkt.num_headers; i++) {
					lineBuffer.append(ospf_get_lsa_hdr( ddPkt.lsaheaders[i] ));
					lineBuffer.append(" }");
				}
				
				break;
			case Packet.LSREQUEST:
				OSPFLSReqPkt lsrPkt = (OSPFLSReqPkt)ospfHdr.ospfData;
				if(lsrPkt == null) break;
				
				for(int i = 0; i < lsrPkt.num_reqs; i++ ) {
					LSAId li = lsrPkt.reqlsas[i];
					lineBuffer.append(" {");
					lineBuffer.append(ospf_get_lstype(li.lstype,li.lsid,li.advrouter,"LinkStateType"));
					lineBuffer.append(" }");
				}
				
				break;
			case Packet.LSUPDATE:
				OSPFLSUpdPkt lsuPkt = (OSPFLSUpdPkt)ospfHdr.ospfData;
				if(lsuPkt == null) break;
				
				for(int i = 0; i < lsuPkt.numlsa; i++ ) {
					LSAHdr lsa = lsuPkt.lsas[i];
					
					lineBuffer.append(ospf_get_lsa(lsa));
				}
				
				break;
			case Packet.LSACK:
				OSPFLSAckPkt lsaPkt = (OSPFLSAckPkt)ospfHdr.ospfData;
				if(lsaPkt == null) break;
				
				for(int i = 0; i < lsaPkt.num_lsas; i++ ) {
					LSAHdr lsa = lsaPkt.lsas[i];
					
					lineBuffer.append(ospf_get_lsa_hdr(lsa));
					lineBuffer.append(" }");
				}
				
				break;
			default:
				/* print nothing */
				break;
		}
		
		lineBuffer.append("\n");
		out.print(lineBuffer);
      		lineBuffer.setLength(0);
      
  	} catch (IOException e) {
  		e.printStackTrace();
  	}
  }

  private String ospf_get_lsa( LSAHdr lsa ) {
  	
  	String l = ospf_get_lsa_hdr( lsa );
  	
  	switch(lsa.linktype) {
  		case LSA.ROUTER_LSA:
 			if (lsa.lsaData == null) break;
 			
 			RtrLSA rtrlsa = (RtrLSA)lsa.lsaData;
 			
  			if ( (rtrlsa.flags & 0x01) != 0 ) l += " B";
  			if ( (rtrlsa.flags & 0x02) != 0 ) l += " E";
  			if ( (rtrlsa.flags & 0x04) != 0 ) l += " V";
  		
  			for(int i = 0; i < rtrlsa.numlinks; i++ ) {
  				
  				l += " {";
  				
  				RtrLink lnk = rtrlsa.links[i];
  				
  				switch( lnk.linktype ) {
  					case OSPF.VIRTUAL_LINK:
  						l +=" virt";
  						break;
  					case OSPF.POINT_TO_POINT:
  						l +=" nbrid "+IPtoString(lnk.linkid);
  						l +=" if "+IPtoString(lnk.linkdata);
  						break;
  					case OSPF.TO_TRANSIT_NET:
  						l +=" dr "+IPtoString(lnk.linkid);
  						l +=" if "+IPtoString(lnk.linkdata);
  						break;
  					case OSPF.TO_STUB_NET:
  						l +=" net "+IPtoString(lnk.linkid);
  						l +=" mask "+IPtoString(lnk.linkdata);
  						break;
  					default:
  						l += " ??RouterLinksType "+lnk.linktype+"??";
  						break;	
  				}
  				  				
  				/* TOS omitted - not implemented in SSF.OS.OSPF */
  				l += " tos 0 metric "+lnk.metric;
  				
  				l += " }";
  			}
  			break;
  		case LSA.NETWORK_LSA:
  		case LSA.SUMMARY_NETWORK_LSA:
  		case LSA.SUMMARY_ASBR_LSA:
  		case LSA.AS_EXTERNAL_LSA:
  		default:
  			l += " NotImplemented";
  			break;
  	}
  	
  	l += " }";
  	
  	return l;
  }

  
  private String ospf_get_lsa_hdr( LSAHdr lsa ) {
  	String hdr;
  	
  	hdr = " {"+ospf_get_option_string(lsa.options);
  	hdr += " S "+Integer.toHexString(lsa.lssequence);
  	hdr += " age "+ospf_get_age( lsa.lsage );
  	hdr += ospf_get_lstype( lsa.linktype, lsa.lsid, lsa.advrouter, "ls_type" );
  	
  	return hdr;
  }
  
  private String ospf_get_lstype(int type, int id, int rtr, String fmt) {
  	
  	String t = "";
  	
  	switch(type) {
  		case LSA.ROUTER_LSA:
  			t = " rtr "+IPtoString(rtr);
  			break;
  		case LSA.NETWORK_LSA:
  			t = " net dr "+IPtoString(rtr)+" if "+IPtoString(id);
  			break;
  		case LSA.SUMMARY_NETWORK_LSA:
  			t = " sum "+IPtoString(id)+" abr "+IPtoString(rtr);
  			break;
  		case LSA.SUMMARY_ASBR_LSA:
  			t = " abr "+IPtoString(rtr)+" rtr "+IPtoString(id);
  			break;
  		case LSA.AS_EXTERNAL_LSA:
  			t = " ase "+IPtoString(id)+" rtr "+IPtoString(rtr);
  			break;
  		default:
  			t =" "+fmt+" "+type;
  			break;
  	}
  	
  	return t;
  }

  
  private String ospf_get_age( short age ) {
  	String a = "";
  	/* do some formatting here */
  	a += age;
  	
  	return a;
  	
  }

  
  
  private String ospf_get_option_string( byte opts ) {
  	String ostr = "";
  	
  	if ( (opts & 0x01) != 0 ) ostr += " T";
  	if ( (opts & 0x02) != 0 ) ostr += " E";
  	if ( (opts & 0x04) != 0 ) ostr += " MC";
  	
  	return ostr;
  }
 
  
  /* end djacob */
  
  // ported from SSF.Net.Util 
  public static String IPtoString (int ipAddr){
    int a = (ipAddr >> 24) & 0xFF;
    int b = (ipAddr >> 16) & 0xFF;
    int c = (ipAddr >>  8) & 0xFF;
    int d = (ipAddr      ) & 0xFF;
    return (a+"."+b+"."+c+"."+d);
  }

  public int byteToInt(boolean swap, byte[] b){
    int len = b.length;
    if((len < 1) || (len > 4)) {
      System.err.println("Usage error: only 1~4 bytes integer supported");
      System.exit(1);
    }
    int n = 0;
    if (swap) {
      switch (len) {
      case 4:
	n |= (b[3]&0xff) << 24;
      case 3:
	n |= (b[2]&0xff) << 16;
      case 2:
	n |= (b[1]&0xff) << 8;
      case 1:
	n |= b[0]&0xff;
      }
    } else {
      switch (len) {
      case 4:
	n  = (b[0]&0xff) << 24;
	n |= (b[1]&0xff) << 16;
	n |= (b[2]&0xff) << 8;
	n |= b[3]&0xff;
	break;
      case 3:
	n  = (b[0]&0xff) << 16;
	n |= (b[1]&0xff) << 8;
	n |= b[2]&0xff;
	break;
      case 2:
	n  = (b[0]&0xff) << 8;
	n |= b[1]&0xff;
	break;
      case 1:
	n  = b[0]&0xff;
	break;
      }
    }
    return n;
  }
  
	public static void main (String[] args) {
    	if(args.length < 1){
      		System.err.println("usage:OSPFDumpPro <binary tcpdump filename>\n");
      		return;
      	}
			 
      	String filename = args[0];
	
		try {
            OSPFDumpPro dump = new OSPFDumpPro(filename,"");
    	} catch (IOException e) {
      		System.out.println(e);
    	} 
  	}
}
